/*
 * Copyright (C) 2020-present, kinbug All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitee.kinbug.sniper.common.util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;

import com.gitee.kinbug.sniper.common.entity.Earning;
import com.gitee.kinbug.sniper.common.entity.Statistics;
import com.gitee.kinbug.sniper.common.enums.OrderActionEnum;
import com.gitee.kinbug.sniper.common.enums.SymbolEnum;

import lombok.extern.slf4j.Slf4j;

/**
 * -一些计算的工具类
 * @ClassName: CoreUtil
 * @author kinbug
 * @date 2020-12-14
 */
@Slf4j
public class CoreUtil {
	/**
	 * -发送买入消息通知
	 * @param symbol 币对
	 * @param orderAction 买卖方向
	 * @param buyPrice 买入均价
	 * @param buyNum 买入量
	 * @return void 返回类型
	 */
	public static void sendBuys(String dingtalkUrl, SymbolEnum symbol, long id, OrderActionEnum orderAction,
			BigDecimal buyPrice, BigDecimal buyNum, BigDecimal avgPrice, BigDecimal stopLoss, String reason,
			boolean ifSendMsg) {
		String time = Consts.SDF.format(new Date()); // 时间戳转换日期
		String isBuyStr = orderAction == OrderActionEnum.BUYUP ? "买涨[向上]" : "买跌[向下]";
		String msg = symbol.getCode() + ":[" + time + "]，" + id + "\n " + "推荐" + isBuyStr + "：" + reason + "买价："
				+ buyPrice + " 仓比：" + buyNum + "% 持仓均价：" + avgPrice + " 移动止损：" + stopLoss;
		log.warn(msg.replace("\n", ""));
		if (ifSendMsg) {
			DingTalkUtil.sendMsg(dingtalkUrl, msg, false, null);
		}
	}

	/**
	 * -发送卖出消息通知
	 * @Title sendShell
	 * @param symbol 币对
	 * @param orderAction 买卖方向
	 * @param buyPrice 买入均价
	 * @param buyNum 买入量
	 * @param sellPrice 卖出价
	 * @param lever 杠杠数
	 * @param reason 卖出原因
	 * @return void 返回类型
	 */
	public static void sendSell(String dingtalkUrl, SymbolEnum symbol, long id, OrderActionEnum orderAction,
			BigDecimal buyPrice, BigDecimal buyNum, BigDecimal sellPrice, Integer lever, BigDecimal changepercent,
			String reason, BigDecimal earn, boolean ifSendMsg) {
		String time = Consts.SDF.format(new Date()); // 时间戳转换日期
		String isBuyStr = orderAction == OrderActionEnum.BUYUP ? "买涨[向上]" : "买跌[向下]";
		String meme = earn.compareTo(BigDecimal.ZERO) > 0 ? "[老板]" : "[对不起]";
		String msg = symbol.getCode() + ":[" + time + "]，" + id + "\n " + reason + "，" + isBuyStr + "均价：" + buyPrice
				+ " 卖价：" + sellPrice + "，总的仓位：" + buyNum + "% " + lever + "倍杠杆收益：" + changepercent + "% 本次收益：" + earn
				+ meme;
		log.warn(msg.replace("\n", ""));
		log.warn("");
		if (ifSendMsg) {
			DingTalkUtil.sendMsg(dingtalkUrl, msg, false, null);
		}
	}

	/**
	 * -发送移动止盈消息
	 * @Title sendShell
	 * @param symbol 币对
	 * @param buyPrice 买入均价
	 * @param sellPrice 卖出价
	 * @return void 返回类型
	 */
	public static void sendStop(String dingtalkUrl, String symbol, long id, OrderActionEnum orderAction, BigDecimal buyPrice,
			BigDecimal stopPrice, BigDecimal newPrice, boolean ifSendMsg) {
		String time = Consts.SDF.format(new Date()); // 时间戳转换日期
		String isBuyStr = orderAction == OrderActionEnum.BUYUP ? "买涨" : "买跌";
		String msg = symbol + ":[" + time + "]，" + id + "\n " + "计划止盈价：" + stopPrice + isBuyStr + "均价：" + buyPrice
				+ " 当前价：" + newPrice;
		log.warn(msg.replace("\n", ""));
		if (ifSendMsg) {
			DingTalkUtil.sendMsg(dingtalkUrl, msg, false, null);
		}
	}

	/**
	 * -发送收益
	 * @param symbol 币对
	 * @param earnings 收益集合
	 * @return void 返回类型
	 * @throws
	 */
	public static void sendGain(String dingtalkUrl, String symbol, List<Earning> earnings, boolean ifSendMsg, String acountNum) {
		LocalDate localDate = LocalDate.now();
		final int day = localDate.getDayOfYear();
		BigDecimal todayGain = earnings.stream().filter(e -> e.getTime().getDayOfYear() == day).map(e -> e.getEarn())
				.reduce(BigDecimal.ZERO, BigDecimal::add);
		Statistics s10 = cycleCount(earnings, 10);
		Statistics sAll = cycleCount(earnings, null);
		BigDecimal backtest = BigDecimal.ZERO;
		BigDecimal maxBacktest = BigDecimal.ZERO;
		for (int i = 0; i < earnings.size(); i++) {
			BigDecimal gainOne = earnings.get(i).getEarn();
			if (gainOne.compareTo(BigDecimal.ZERO) < 0) {
				backtest = backtest.add(gainOne);
			} else {
				if (backtest.compareTo(maxBacktest) < 0) {
					maxBacktest = backtest;
				}
				backtest = BigDecimal.ZERO;
			}
		}

		String msg = symbol + ":[" + localDate + "],今天收益：" + todayGain + ";\n" + "账户权益：" + acountNum + ";\n" + "十天内多单数："
				+ s10.getLongNum() + "，胜率：" + s10.getLongWinRate() + "%，总收益：" + s10.getLongGains() + "\n" + "十天内空单数："
				+ s10.getShortNum() + "，胜率：" + s10.getShortWinRate() + "%，总收益：" + s10.getShortGains() + "\n" + "历史总挂单数："
				+ earnings.size() + "，胜率：" + sAll.getTotalWinRate() + "%，总收益：" + sAll.getTotalGains() + "\n" + "策略最大回测："
				+ maxBacktest.divide(new BigDecimal(10), 2, RoundingMode.DOWN) + "%";
		log.warn(msg);
		if (ifSendMsg) {
			DingTalkUtil.sendMsg(dingtalkUrl, msg, false, null);
		}
	}

	/**
	 * -获得%涨幅
	 * @Title getRose
	 * @param (close - open)/open 参数
	 * @return void 返回类型
	 * @throws
	 */
	public static BigDecimal getChangepercent(BigDecimal open, BigDecimal close) {
		BigDecimal changepercent = (close.subtract(open)).multiply(new BigDecimal(100)).divide(open, 2,
				RoundingMode.DOWN);
		return changepercent;
	}

	private static Statistics cycleCount(List<Earning> earnings, Integer period) {
		Statistics statistics = new Statistics();
		if (null == period) {
			for (Earning earning : earnings) {
				statistics.addEarnings(earning);
			}
			return statistics;
		}
		LocalDate localDate = LocalDate.now();
		int year = localDate.getYear();
		int day = localDate.getDayOfYear() - period;
		if (day < 0) {
			day = 0;
		}
		for (Earning earning : earnings) {
			int barDay = earning.getTime().getDayOfYear();
			int barYear = earning.getTime().getYear();
			if (barYear == year && barDay > day) {
				statistics.addEarnings(earning);
			}
		}
		return statistics;
	}

	public static LocalDateTime getDateTimeOfTimestamp(long timestamp) {
		Instant instant = Instant.ofEpochMilli(timestamp);
		ZoneId zone = ZoneId.systemDefault();
		return LocalDateTime.ofInstant(instant, zone);
	}

	public static long getTimestampOfDateTime(LocalDateTime localDateTime) {
		ZoneId zone = ZoneId.systemDefault();
		Instant instant = localDateTime.atZone(zone).toInstant();
		return instant.toEpochMilli();
	}

}
